from django.template import RequestContext
from django.shortcuts import render_to_response
from RSM.algorithm.feasibility import COR_algorithm
from RSM.my_movies.models import Movie
from RSM.util import verifySessionValidity, getRSMUser, getRSMGroup, getTitle

recommendationLimit = 5

def recommend(request):
    nonValidSessionFlag = verifySessionValidity(request)
    if nonValidSessionFlag:
        return nonValidSessionFlag
    
    currUser = getRSMUser(request.user.username)
 
    recommendSeen = bool(request.POST.get(u'recommendSeen'))
    limitWorld = bool(request.POST.get(u'limitWorld'))
    if limitWorld:
        #after clicking 'recommend' button with the 'limit world' checkbox checked
        return __recommend_limitWorld(request, recommendSeen)
    
    if request.POST.get(u'movieList'):
        #redirected after updating likes, blacklist, etc.
        return __recommend_afterUpdatingCheckboxes(request, currUser)
    
    #first time in this page:
    return __recommend_firstTime(request, currUser, recommendSeen)



def __recommend_limitWorld(request, recommendSeen):
    return render_to_response('recommendation/chooseMovieSet.html', {'friendList': request.POST.getlist(u'friendList'), 'groupList': request.POST.getlist(u'groupList'), 'recommendSeen': recommendSeen, 'movies': map(getTitle, Movie.objects.all()) }, context_instance=RequestContext(request))


def __recommend_afterUpdatingCheckboxes(request, currUser):
    movieList = request.POST.getlist(u'movieList')
    new_seen = request.POST.getlist(u'seen')
    new_like = request.POST.getlist(u'like')
    new_blacklist = request.POST.getlist(u'blacklist')
    __updateList(currUser.seen, new_seen, movieList)
    __updateList(currUser.likes, new_like, movieList)
    __updateList(currUser.blacklist, new_blacklist, movieList)
    currUser.save()
   
    context = set(map(getTitle, currUser.likes.all()))
    seen = set(map(getTitle, currUser.seen.all()))
    blacklist = set(map(getTitle, currUser.blacklist.all()))
   
    movieResults = map(lambda r: Movie.objects.get(title=r), movieList)
    return render_to_response('recommendation/results.html', {'results': [(m.title, m.year, m.link, (m.title in context), (m.title in seen), (m.title in blacklist))
                                                                              for m in movieResults]}, context_instance=RequestContext(request))


def __recommend_firstTime(request, currUser, recommendSeen):
    context = set(map(getTitle, currUser.likes.all()))
    seen = set(map(getTitle, currUser.seen.all()))
    blacklist = set(map(getTitle, currUser.blacklist.all()))
    
    friends = set(map(lambda uname: getRSMUser(uname), request.POST.getlist(u'friendList')))
    groups = map(lambda gn: getRSMGroup(currUser.user.username, gn), request.POST.getlist(u'groupList'))
    for g in groups:
        friends |= set(g.members.all())
    
    friendsContext = context.copy()
    if not recommendSeen:
        friendsSeen = seen.copy()
    friendsBlacklist = blacklist.copy()
    for friend in friends:
        friendsContext |= set(map(getTitle, friend.likes.all()))
        if not recommendSeen:
            friendsSeen |= set(map(getTitle, friend.seen.all()))
        friendsBlacklist |= set(map(getTitle, friend.blacklist.all()))
    
    world = __getWorld(friendsSeen if not recommendSeen else set(), friendsBlacklist)
    if request.POST.get(u'selectedList'):
        #after limiting world
        world &= set(request.POST.getlist(u'selectedList'))

    if not world:
        return render_to_response('recommendation/noMatch.html', context_instance=RequestContext(request))
    world = list(world)
    
    if not friendsContext:
        results = world[:recommendationLimit]
    else:
        results = COR_algorithm("Mutual Information", "Normalized Mutual Information", list(friendsContext), world)[:recommendationLimit]
    movieResults = map(lambda r: Movie.objects.get(title=r), results)
    return render_to_response('recommendation/results.html', {'results': [(m.title, m.year, m.link, (m.title in context), (m.title in seen), (m.title in blacklist))
                                                                          for m in movieResults]}, context_instance=RequestContext(request))


def chooseFriends(request):
    nonValidSessionFlag = verifySessionValidity(request)
    if nonValidSessionFlag:
        return nonValidSessionFlag
    
    currUser = getRSMUser(request.user.username)
    friends = currUser.friends.all()
    groups = currUser.groups.all()
    return render_to_response('recommendation/chooseFriends.html', {'friends': friends, 'groups': groups}, context_instance=RequestContext(request))


#Private functions
def __getUnfilteredWorld():
    return map(getTitle, Movie.objects.all())

def __getWorld(seen, blacklist):
    return set(__getUnfilteredWorld()) - seen - blacklist

def __updateList(src, update, all):
    for m in set(all):
        try:
            src.remove(Movie.objects.get(title=m))
        except:
            pass
    for m in set(update):
        try:
            src.add(Movie.objects.get(title=m))
        except:
            pass
    #src = (src.all() - set(all)) | set(update)
